package com.chookss.tools;

import android.content.Context;
import android.content.Intent;

import androidx.localbroadcastmanager.content.LocalBroadcastManager;

import com.chookss.MyApp;
import com.chookss.Urls;

import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class AESEncrypt {
    /**
     * 加密算法
     */
    private static final String KEY_ALGORITHM = "AES";

    /**
     * AES 的 密钥长度，32 字节，范围：16 - 32 字节
     */
    public static final int SECRET_KEY_LENGTH = 32;

    /**
     * 字符编码
     */
    private static final Charset CHARSET_UTF8 = StandardCharsets.UTF_8;

    /**
     * 秘钥长度不足 16 个字节时，默认填充位数
     */
    private static final String DEFAULT_VALUE = "0";
    /**
     * 加解密算法/工作模式/填充方式
     */
    private static final String CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";
    private static final String secretKey = "1990101220181220";
    /**
     * 对文件进行AES加密
     *
     * @param sourceFile 待加密文件
     * @return 加密后的文件
     */
    public static boolean encryptFile(Context context,String sourceFile,String fileName,String dataCode,String tag) {

        try {
            // 创建加密后的文件
            File encryptFile = new File(context.getFilesDir()+ File.separator+ Urls.DOWNLOAD+File.separator+fileName);
            File fromFile=new File(context.getFilesDir()+ File.separator+ Urls.DOWNLOADCache+File.separator+fileName);
            // 根据文件创建输出流
            FileOutputStream outputStream = new FileOutputStream(encryptFile);
            // 初始化 Cipher
            Cipher cipher = initFileAESCipher(secretKey, Cipher.ENCRYPT_MODE);
            // 以加密流写入文件
            CipherInputStream cipherInputStream = new CipherInputStream(
                    new FileInputStream(fromFile), cipher);
            // 创建缓存字节数组
            byte[] buffer = new byte[1024 * 2];
            // 读取
            int len;
            // 读取加密并写入文件
            while ((len = cipherInputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, len);
                outputStream.flush();
            }
            // 关闭加密输入流
            cipherInputStream.close();
            closeStream(outputStream);
            fromFile.delete();
            MyApp.downloadFiles.add(fileName);
            Intent intent=new Intent();
            intent.setAction(tag);
            intent.putExtra("encryptStatus",true);
            intent.putExtra("fileName",fileName);
            intent.putExtra("fileUrl",sourceFile);
            intent.putExtra("dataCode",dataCode);
            LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            Intent intent=new Intent();
            intent.setAction(tag);
            intent.putExtra("encryptStatus",false);
            intent.putExtra("fileName",fileName);
            intent.putExtra("fileUrl",sourceFile);
            intent.putExtra("dataCode",dataCode);
            LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
        }
        return false;
    }

    /**
     * AES解密文件
     *
     * @param dir        解密后的文件存储路径
     */
    public static boolean decryptFile(Context context, String dir,String tag) {
        try {
            // 创建解密文件
            File decryptFile = new File(context.getFilesDir()+ File.separator+ Urls.DOWNLOADCache+File.separator+dir);
            File sourceFile=new File(context.getFilesDir()+ File.separator+ Urls.DOWNLOAD+File.separator+dir);
            // 初始化Cipher
            Cipher cipher = initFileAESCipher(secretKey, Cipher.DECRYPT_MODE);
            // 根据源文件创建输入流
            FileInputStream inputStream = new FileInputStream(sourceFile);
            // 获取解密输出流
            CipherOutputStream cipherOutputStream = new CipherOutputStream(
                    new FileOutputStream(decryptFile), cipher);
            // 创建缓冲字节数组
            byte[] buffer = new byte[1024 * 2];
            int len;
            // 读取解密并写入
            while ((len = inputStream.read(buffer)) >= 0) {
                cipherOutputStream.write(buffer, 0, len);
                cipherOutputStream.flush();
            }
            // 关闭流
            cipherOutputStream.close();
            closeStream(inputStream);
            Intent intent=new Intent();
            intent.setAction(tag);
            intent.putExtra("decryptStatus",true);
            LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            Intent intent=new Intent();
            intent.setAction(tag);
            intent.putExtra("decryptStatus",false);
            LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
        }
        return false;
    }

    /**
     * 初始化 AES Cipher
     *
     * @param secretKey  密钥
     * @param cipherMode 加密模式
     * @return 密钥
     */
    private static Cipher initFileAESCipher(String secretKey, int cipherMode) {
        try {
            // 创建密钥规格
            SecretKeySpec secretKeySpec = getSecretKey(secretKey);
            // 获取密钥
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            // 初始化
            cipher.init(cipherMode, secretKeySpec, new IvParameterSpec(new byte[cipher.getBlockSize()]));
            return cipher;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 关闭流
     *
     * @param closeable 实现Closeable接口
     */
    private static void closeStream(Closeable closeable) {
        try {
            if (closeable != null) closeable.close();
        } catch (Exception e) {
           e.printStackTrace();
        }
    }

    /**
     * 使用密码获取 AES 秘钥
     */
    public static SecretKeySpec getSecretKey(String secretKey) {
        secretKey = toMakeKey(secretKey, SECRET_KEY_LENGTH, DEFAULT_VALUE);
        return new SecretKeySpec(secretKey.getBytes(CHARSET_UTF8), KEY_ALGORITHM);
    }
    /**
     * 如果 AES 的密钥小于 {@code length} 的长度，就对秘钥进行补位，保证秘钥安全。
     *
     * @param secretKey 密钥 key
     * @param length    密钥应有的长度
     * @param text      默认补的文本
     * @return 密钥
     */
    private static String toMakeKey(String secretKey, int length, String text) {
        // 获取密钥长度
        int strLen = secretKey.length();
        // 判断长度是否小于应有的长度
        if (strLen < length) {
            // 补全位数
            StringBuilder builder = new StringBuilder();
            // 将key添加至builder中
            builder.append(secretKey);
            // 遍历添加默认文本
            for (int i = 0; i < length - strLen; i++) {
                builder.append(text);
            }
            // 赋值
            secretKey = builder.toString();
        }
        return secretKey;
    }
}
